package com.example.infrastructure.api.organization;

import com.example.infrastructure.api.organization.vo.Condition;
import com.example.infrastructure.api.organization.vo.OrganizationVo;
import com.example.infrastructure.api.person.dto.PersonDto;
import com.example.infrastructure.application.OrganizationApplication;
import com.example.infrastructure.application.PersonApplication;
import com.example.infrastructure.domain.organization.aggregate.Organization;
import com.example.infrastructure.domain.person.aggregate.Person;
import com.example.infrastructure.domain.person.aggregate.valueObject.PersonType;
import com.example.infrastructure.infrastructure.mapper.organization.OrganizationMapper;
import com.example.infrastructure.infrastructure.mapper.person.PersonMapper;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * TODO
 *
 * @author lxh
 * @date 2020/11/17 下午12:45
 **/
@RestController
@RequestMapping("/organizations")
@Validated
public class OrganizationApi {
    private final OrganizationApplication organizationApplication;
    private final PersonApplication personApplication;
    private final PersonMapper personMapper;

    public OrganizationApi(
            OrganizationApplication organizationApplication,
            PersonApplication personApplication,
            PersonMapper personMapper) {
        this.organizationApplication = organizationApplication;
        this.personApplication = personApplication;
        this.personMapper = personMapper;
    }

    @GetMapping("/{orgId}")
    public Organization findOneByOrgId(@PathVariable String orgId) {
        return organizationApplication
                .findOne(orgId)
                .orElseThrow(() -> new IllegalArgumentException("不存在该组织： " + orgId));
    }

    @GetMapping("/{orgId}/people")
    public List<PersonDto> findPeopleByOrgId(@PathVariable String orgId, String type) {
        List<Person> people =
                personApplication.findPersonByOrgId(orgId, StringUtils.hasText(type) ? PersonType.valueOf(type) : null);
        return people.stream().map(personMapper::toDto).collect(Collectors.toList());
    }

    @GetMapping("/{orgId}/manager")
    public PersonDto findManager(@PathVariable String orgId) {
        Person manager =
                personApplication.findPersonByOrgId(orgId, PersonType.MANAGER).get(0);
        return personMapper.toDto(manager);
    }

    @GetMapping
    public List<Organization> findOrganizations(OrganizationVo vo, HttpServletRequest request) {
        if (!isGetParametersLegal(request.getParameterMap().keySet())) {
            return Collections.emptyList();
        }
        return organizationApplication.findOrganizations(OrganizationMapper.INSTANCE.toDo(vo));
    }

    @PostMapping("/search")
    public List<Organization> search(@RequestBody @Valid Condition condition) {
        return organizationApplication.search(condition);
    }

    @PostMapping
    public Organization addOrganization(@RequestBody @Valid OrganizationVo organizationVo) {

        if (StringUtils.hasText(organizationVo.getOrgId())) {
            throw new IllegalArgumentException("新增组织机构不需要ID！");
        }
        return organizationApplication.save(OrganizationMapper.INSTANCE.toDo(organizationVo));
    }

    @PutMapping
    public Organization updateOrganization(@RequestBody @Valid OrganizationVo organizationVo) {
        if (!StringUtils.hasText(organizationVo.getOrgId())) {
            throw new IllegalArgumentException("更新组织机构请带上ID！");
        }
        return organizationApplication.save(OrganizationMapper.INSTANCE.toDo(organizationVo));
    }

    @DeleteMapping("/{orgId}")
    public Map<String, String> deleteOrganization(@PathVariable String orgId) {
        organizationApplication.delete(orgId);
        HashMap<String, String> map = new HashMap<>(1);
        map.put("msg", "删除成功！");
        return map;
    }

    /**
     * GET请求参数是否在 {@link OrganizationVo} 查询条件范围内。
     * <br/>
     * 对于不在查询条件范围的请求参数，API可根据此方法直接返回而不需要向下流转。
     */
    private static boolean isGetParametersLegal(Set<String> parameterNames) {
        Set<String> queryConditions = Stream.of(OrganizationVo.class.getDeclaredFields())
                .map(Field::getName)
                .collect(Collectors.toSet());

        Set<String> queryParamNames = parameterNames.stream()
                .map(parameterName -> parameterName.split("\\."))
                .flatMap(Stream::of)
                .collect(Collectors.toSet());

        return queryConditions.containsAll(queryParamNames);
    }
}
